跳到主要内容

几何类型 HXPoint / HXRect

UI 框架里打交道最多的就是坐标和矩形。HiEasyX 定义了一套简洁的几何类型,用来描述屏幕上的点、区域、大小。读完这一节,你就能轻松地算碰撞、算布局、算鼠标是不是点到了某个按钮里面。


基础类型别名

using HXGInt  = int32_t;   // 有符号坐标/尺寸
using HXGUInt = uint32_t; // 无符号计数/索引
信息

HXGInt 而不是裸 int,是为了保证在 32/64 位编译下尺寸一致,避免跨平台时的布局结构体大小漂移。写库代码建议统一用别名。


HXPoint:二维点

struct HXPoint {
HXGInt X;
HXGInt Y;
};

就这么简单,一个 X 一个 Y,表示屏幕上的位置。注意坐标系原点在 左上角Y 向下增长,这是 Windows GUI 的惯例。

HXPoint pos{100, 200};   // 屏幕坐标 (100, 200)
pos.X += 50; // 向右移动 50 像素

HXRect:轴对齐矩形

struct HXRect {
HXGInt Left;
HXGInt Top;
HXGInt Right;
HXGInt Bottom;
};

HiEasyX 的矩形采用 左闭右开 的约定,也就是说:

  • 包含 LeftTop 边界
  • 不包含 RightBottom 边界
HXRect rc{0, 0, 100, 100};  // 宽 100,高 100,右下角像素是 (99, 99)
危险

很多新手会误以为 Right/Bottom 是最后一个像素的坐标。如果是那样,宽度应该是 Right - Left + 1。HiEasyX 用的是 右开区间,宽度直接 Right - Left 即可。这个约定和 Windows 的 RECT 以及很多 2D 图形 API 保持一致。


常用成员方法

判断点是否在矩形内

bool HXRect::PointInside(HXGInt x, HXGInt y) const;
bool HXRect::PointInside(const HXPoint& p) const;
HXRect button{100, 100, 200, 150};
HXPoint mouse{150, 120};

if (button.PointInside(mouse)) {
// 鼠标在按钮里面!
}

计算宽高

HXGInt HXRect::CalWidth() const;   // Right - Left
HXGInt HXRect::CalHeight() const; // Bottom - Top
HXRect win{0, 0, 800, 600};
HXGInt w = win.CalWidth(); // 800
HXGInt h = win.CalHeight(); // 600
提示

写布局代码时,这两个方法出场率极高。比如把一个子控件居中:

HXRect parent{0, 0, 800, 600};
HXRect child{0, 0, 200, 100};

// 水平居中
child.Left = parent.Left + (parent.CalWidth() - child.CalWidth()) / 2;
child.Right = child.Left + child.CalWidth();

// 垂直居中
child.Top = parent.Top + (parent.CalHeight() - child.CalHeight()) / 2;
child.Bottom = child.Top + child.CalHeight();

常用几何运算示例

矩形位移

HXRect MoveRect(const HXRect& rc, HXGInt dx, HXGInt dy) {
return {rc.Left + dx, rc.Top + dy, rc.Right + dx, rc.Bottom + dy};
}

求两矩形交集

HXRect Intersect(const HXRect& a, const HXRect& b) {
HXRect out;
out.Left = std::max(a.Left, b.Left);
out.Top = std::max(a.Top, b.Top);
out.Right = std::min(a.Right, b.Right);
out.Bottom = std::min(a.Bottom, b.Bottom);
// 如果结果无效,宽高会是负数,调用方自行检查
return out;
}

求两矩形并集(最小包围盒)

HXRect Union(const HXRect& a, const HXRect& b) {
return {
std::min(a.Left, b.Left),
std::min(a.Top, b.Top),
std::max(a.Right, b.Right),
std::max(a.Bottom, b.Bottom)
};
}

矩形是否完全包含另一矩形

bool Contains(const HXRect& outer, const HXRect& inner) {
return outer.Left <= inner.Left &&
outer.Top <= inner.Top &&
outer.Right >= inner.Right &&
outer.Bottom >= inner.Bottom;
}

从点和大小构造矩形

HXRect MakeRect(HXGInt x, HXGInt y, HXGInt w, HXGInt h) {
return {x, y, x + w, y + h}; // 右开,所以直接加
}

// 用法
HXRect rc = MakeRect(10, 20, 300, 200); // {10, 20, 310, 220}

和 EasyX 的交互

EasyX 本身也有一套 POINTRECT,但 HiEasyX 的几何类型是独立的。如果你需要混用,通常是在底层渲染或事件处理时做简单转换:

// HiEasyX → EasyX
POINT toEasyX(const HXPoint& p) { return {p.X, p.Y}; }
RECT toEasyX(const HXRect& r) { return {r.Left, r.Top, r.Right, r.Bottom}; }

// EasyX → HiEasyX
HXPoint fromEasyX(const POINT& p) { return {p.x, p.y}; }
HXRect fromEasyX(const RECT& r) { return {r.left, r.top, r.right, r.bottom}; }
信息

大部分情况下你不需要手动转。HiEasyX 的 Painter 和控件 API 内部已经消化掉了这些差异,只有在直接调用 EasyX 原生函数时才可能需要。


一句话总结

类型用途关键方法
HXPoint点坐标X, Y
HXRect轴对齐矩形PointInside(), CalWidth(), CalHeight()
提示

记住 左闭右开,矩形运算就不会翻车。CalWidth() == Right - Left,不包含右边界的那个像素,这和循环里写 for (int i = 0; i < n; ++i) 是一个道理。